package com.gjy.redis.util.scan;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import redis.clients.jedis.Tuple;

import java.util.ArrayList;
import java.util.List;

/**
 * 高效遍历 Sorted Set（有序集合）。
 * 注意：ZSCAN 只能对 member 做 MATCH，score 只能在客户端过滤。
 *
 * @author gjy
 * @version 1.0
 * @since 2025-10-13 16:08:13
 */
public class ZScanUtil {

    /**
     * 完整遍历 ZSET，返回 Tuple（member + score）。
     *
     * @param jedis   Jedis 实例
     * @param key     ZSET 键名
     * @param pattern MATCH member 的 glob pattern
     * @param count   每次返回期望的成员数
     * @return 所有成员（Tuple 包含 score）
     */
    public static List<Tuple> zScanAll(Jedis jedis,
                                       String key,
                                       String pattern,
                                       int count) {
        List<Tuple> result = new ArrayList<>();
        String cursor = ScanParams.SCAN_POINTER_START;

        ScanParams params = new ScanParams().count(count);
        if (pattern != null && !pattern.isEmpty()) {
            params.match(pattern);
        }

        while (!cursor.equals(ScanParams.SCAN_POINTER_START) || result.isEmpty()) {
            ScanResult<Tuple> rs = jedis.zscan(key, cursor, params);
            result.addAll(rs.getResult());
            cursor = rs.getCursor();
        }
        return result;
    }

    /**
     * 示例：仅保留 score 在 [minScore, maxScore] 区间的成员（客户端过滤）。
     */
    public static List<Tuple> zScanScoreRange(Jedis jedis,
                                              String key,
                                              double minScore,
                                              double maxScore,
                                              String pattern,
                                              int count) {
        List<Tuple> all = zScanAll(jedis, key, pattern, count);
        List<Tuple> filtered = new ArrayList<>();
        for (Tuple t : all) {
            double s = t.getScore();
            if (s >= minScore && s <= maxScore) {
                filtered.add(t);
            }
        }
        return filtered;
    }

}
